package com.idea.relax.tool.core.excel.easypoi;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.idea.relax.tool.core.DateUtil;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 封装的是EasyPOI-4.1.0版本中的部分常用的Excel导入、导出的API,
 * 比如：导出带有标题+表头格式的Excel、导出大数据量的Excel、
 * 导入格式是第一行标题，第二行表头的Excel、数据校验的导入、
 * 大数据量的导入、图片的导入导出也是支持的.<br/>
 * 假如需要更多的额外操作（比如给导出的表格加底色），可以参照官网进行，可以不使用这个工具类去实现<br/>
 * EasyPOI官网：<link>http://www.wupaas.com/<link/><br/>
 * EasyPOI官方文档：<link>http://doc.wupaas.com/docs/easypoi/easypoi-1c0u6ksp2r091<link/>
 *
 * @className: ExcelUtil
 * @description:
 * @author: salad
 * @date: 2021/7/17
 **/
@SuppressWarnings("all")
public class ExcelUtil {

    private static final String SUF_XLS = ".xls";

    private static final String SUF_XLSX = ".xlsx";


    private ExcelUtil() {
    }


    public static <T> void export(HttpServletResponse response, Class<T> clazz, String sheetName,
                              Collection<T> dataList) {
        try {
            ExportParams exportParams = new ExportParams(DateUtil.format(LocalDateTime.now(),
                    "yyyyMMddHHmmss"), sheetName);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, clazz, dataList);
            ServletOutputStream os = response.getOutputStream();
            write(os, workbook);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    //写出数据
    private static void write(OutputStream os, Workbook workbook) throws IOException {
        workbook.write(os);
        closeExport(os, workbook);
    }


    /***********************导入************************/

    public static <T> List<T> read(MultipartFile file, Class<T> clazz) {
        try {
            return readDataList(file, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static <T> List<T> readDataList(MultipartFile file, Class<T> clazz) throws Exception {
        ImportParams importParams = new ImportParams();
        importParams.setTitleRows(1);
        importParams.setHeadRows(1);
        String filename = file.getOriginalFilename();
        if (StringUtils.isEmpty(filename)) {
            throw new RuntimeException("请上传文件!");
        } else if (!StringUtils.endsWithIgnoreCase(filename, SUF_XLS)
                && !StringUtils.endsWithIgnoreCase(filename, SUF_XLSX)) {
            throw new RuntimeException("请上传正确的excel文件!");
        } else {
            InputStream is = new BufferedInputStream(file.getInputStream());
            return read(is, clazz, importParams);
        }
    }


    public static <T> void save(MultipartFile file, Class<T> clazz, Importer<T> importer) {
        try {
            importer.save(readDataList(file, clazz));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //读取Excel中的数据
    private static <T> List<T> read(InputStream inputstream, Class<?> clazz, ImportParams params) throws Exception {
        return ExcelImportUtil.importExcel(inputstream, clazz, params);
    }

/***********************变种导出（不依靠@Excel注解）************************/

    /**
     * 创建基本的ExcelExportEntity对象（相当于@Excel注解）
     *
     * @param name 表头的名称
     * @param key  如果是MAP类型的导出,而不是基于注解对象的导出方式,这个是map的key
     * @return ExcelExportEntity对象
     */
    public static ExcelExportEntity createExcelCol(String name, Object key) {
        return new ExcelExportEntity(name, key);
    }

    /**
     * 创建基本的ExcelExportEntity对象的集合,假如不需要太多的配置，推荐使用该方法批量创建
     *
     * @param excelCols LinkedHashMap类型的name与key映射的Map
     * @return 多个ExcelExportEntity构成的List集合
     */
    public static List<ExcelExportEntity> createExcelCols(LinkedHashMap<String, Object> excelCols) {
        Set<String> colNames = excelCols.keySet();
        List<ExcelExportEntity> excelColList = new ArrayList<ExcelExportEntity>();
        colNames.forEach(colName -> {
            excelColList.add(new ExcelExportEntity(colName, excelCols.get(colName)));
        });
        return excelColList;
    }


    /**
     * 关闭流 （非大数据量导出用这个方法）
     *
     * @param os
     * @param workbook
     */
    public static void closeExport(OutputStream os, Workbook workbook) {
        if (os != null) {
            try {
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                os = null;
            }
        }
        if (workbook != null) {
            try {
                workbook.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                workbook = null;
            }
        }

    }

}


